/*
* AUTHOR: Kevin Lam
*/
package com.apps.datastore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Logger;
import com.apps.datastore.dao.CachedCourseInformationObject;
import com.apps.datastore.dao.ContactInformationObject;
import com.apps.datastore.dao.ContactInformationObject.CARRIER;
import com.apps.datastore.dao.LoginInformationObject;
import com.apps.datastore.dao.UniqueCourseObject;
import com.apps.outgoing.EmailNotifier;
import com.apps.outgoing.SMSNotifier;
import com.apps.services.UBCSectionDetailService;
import com.apps.utils.BCryptUtils;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Transaction;
public class NotifierDatastore {
private static final Logger log = Logger.getLogger(NotifierDatastore.class
.getName());
private DatastoreService datastore;
public NotifierDatastore() {
datastore = DatastoreServiceFactory.getDatastoreService();
}
public void dropSchema() {
Query q = new Query();
q.setKeysOnly();
List<Entity> l = datastore.prepare(q).asList(
FetchOptions.Builder.withDefaults());
for (Iterator i = l.iterator(); i.hasNext();) {
Entity e = (Entity) i.next();
log.info("deleting " + e.getKey());
System.out.println("deleting " + e.getKey());
datastore.delete(e.getKey());
}
}
public void initSchema() {
Entity e = new Entity("Unique Course Set", "COURSE_ID_SET");
datastore.put(e);
e = new Entity("Cache List", "CACHE_LIST");
datastore.put(e);
e = new Entity("Contact Information Set", "CONTACT_SET");
datastore.put(e);
e = new Entity("Login Information Set", "LOGIN_SET");
datastore.put(e);
e = new Entity("Account Information Set", "ACCOUNT_SET");
datastore.put(e);
}
public List<UniqueCourseObject> getCacheUniqueCourseObjectList()
throws EntityNotFoundException {
List<Entity> cel = getCacheEntityList();
List<UniqueCourseObject> cl = new ArrayList<UniqueCourseObject>();
for (Iterator i = cel.iterator(); i.hasNext();) {
Entity e = (Entity) i.next();
cl.add(getUniqueCourse((Key) e.getProperty("courseKey")));
}
return cl;
}
public List<CachedCourseInformationObject> getCachedCourseInformationObjectList()
throws EntityNotFoundException {
List<Entity> cel = getCacheEntityList();
List<CachedCourseInformationObject> cciol = new ArrayList<CachedCourseInformationObject>();
for (Iterator i = cel.iterator(); i.hasNext();) {
Entity e = (Entity) i.next();
cciol.add(getCourseInformation(e.getKey()));
}
return cciol;
}
public List<ContactInformationObject> getContactEntryList(
UniqueCourseObject uco) throws EntityNotFoundException {
Query q = new Query("Cache");
q.addFilter("courseKey", Query.FilterOperator.EQUAL,
getUniqueCourseEntity(uco).getKey());
Entity qe = datastore.prepare(q).asSingleEntity();
List<Entity> ceel = getContactEntryEntityList(qe.getKey());
List<ContactInformationObject> ciol = new ArrayList<ContactInformationObject>();
for (Iterator i = ceel.iterator(); i.hasNext();) {
Entity e = (Entity) i.next();
ciol.add(getContactInformation((Key) e.getProperty("contactKey")));
}
return ciol;
}
public boolean addCourse(UniqueCourseObject uco)
throws EntityNotFoundException {
boolean b = checkCourseExist(uco);
if (!b) {
Entity course = createUniqueCourseEntity(uco);
createCacheEntity(course.getKey());
}
return !b;
}
public LoginInformationObject getLoginInformationObject(String username) {
Query q = new Query("Login Information");
q.addFilter("username", Query.FilterOperator.EQUAL, username);
Entity qe = datastore.prepare(q).asSingleEntity();
String password = (String) qe.getProperty("password");
boolean active = (Boolean) qe.getProperty("active");
LoginInformationObject lio = new LoginInformationObject(username,password,active);
return lio;
}
public boolean validateLogin(String username) {
Query q = new Query("Login Information");
q.addFilter("username", Query.FilterOperator.EQUAL, username);
Entity qe = datastore.prepare(q).asSingleEntity();
boolean b = !(Boolean) qe.getProperty("active");
if (b)
qe.setProperty("active", true);
datastore.put(qe);
return b;
}
private void createLoginInformationEntity(LoginInformationObject lio){
Transaction txn = datastore.beginTransaction();
Key k = KeyFactory.createKey("Login Information Set", "LOGIN_SET");
Entity e = new Entity("Login Information", k);
e.setProperty("username", lio.getUsername());
e.setProperty("password", lio.getPassword());
datastore.put(e);
txn.commit();
}
public boolean addLogin(LoginInformationObject lio){
boolean b = checkLoginExist(lio);
if(!b)
createLoginInformationEntity(lio);
return !b;
}
public boolean checkLoginExist(LoginInformationObject lio){
Query q = new Query("Login Information");
q.addFilter("username", Query.FilterOperator.EQUAL,
lio.getUsername());
PreparedQuery pq = datastore.prepare(q);
if (pq.countEntities(FetchOptions.Builder.withDefaults()) == 0)
return false;
return true;
}
public boolean addNotifier(UniqueCourseObject uco,
ContactInformationObject cio) throws EntityNotFoundException {
boolean b = checkNotifierExist(uco, cio);
if (!b){
Entity contactInfo = createContactInformationEntity(cio);
createContactEntryEntity(uco, contactInfo.getKey());
}
return !b;
}
private UniqueCourseObject getUniqueCourse(Key courseKey)
throws EntityNotFoundException {
Entity e = datastore.get(courseKey);
UniqueCourseObject uco = new UniqueCourseObject(
(String) e.getProperty("departmentName"),
(String) e.getProperty("courseNumber"),
(String) e.getProperty("sectionNumber"));
return uco;
}
private CachedCourseInformationObject getCourseInformation(Key cacheKey)
throws EntityNotFoundException {
Entity e = datastore.get(cacheKey);
CachedCourseInformationObject ccio = new CachedCourseInformationObject(
(Long) e.getProperty("generalSeats"),
(Long) e.getProperty("restrictedSeats"));
return ccio;
}
private List<Entity> getContactInformationEntityList() {
Query q = new Query("Contact Information");
Key k = KeyFactory.createKey("Contact Information Set", "CONTACT_SET");
q.setAncestor(k);
List<Entity> results = datastore.prepare(q).asList(
FetchOptions.Builder.withDefaults());
return results;
}
private ContactInformationObject getContactInformation(Key contactKey)
throws EntityNotFoundException {
Entity e = datastore.get(contactKey);
ContactInformationObject cio = new ContactInformationObject(
(String) e.getProperty("emailAddress"),
(String) e.getProperty("phoneNumber"),
(Long) e.getProperty("seatConfig"),
(Long) e.getProperty("notifyConfig"),
(String) e.getProperty("carrier"));
return cio;
}
private Entity createCacheEntity(Key courseKey)
throws EntityNotFoundException {
Key k = KeyFactory.createKey("Cache List", "CACHE_LIST");
UBCSectionDetailService w = new UBCSectionDetailService();
w.initContent(getUniqueCourse(courseKey));
Entity e = new Entity("Cache", k);
e.setProperty("courseKey", courseKey);
e.setProperty("generalSeats", w.getGenSeatsRemain());
e.setProperty("restrictedSeats", w.getRestrictSeatsRemain());
datastore.put(e);
return e;
}
private void destroyCacheEntity(Key cacheKey) {
Query q = new Query();
q.setAncestor(cacheKey);
q.setKeysOnly();
List<Entity> results = datastore.prepare(q).asList(
FetchOptions.Builder.withDefaults());
for (Iterator i = results.iterator(); i.hasNext();) {
Transaction txn = datastore.beginTransaction();
Entity e = (Entity) i.next();
datastore.delete(e.getKey());
txn.commit();
}
}
private List<Entity> getCacheEntityList() {
Query q = new Query("Cache");
Key k = KeyFactory.createKey("Cache List", "CACHE_LIST");
q.setAncestor(k);
List<Entity> results = datastore.prepare(q).asList(
FetchOptions.Builder.withDefaults());
return results;
}
public void updateCache() throws EntityNotFoundException {
List<Entity> cel = getCacheEntityList();
for (Iterator i = cel.iterator(); i.hasNext();) {
Entity e = (Entity) i.next();
UBCSectionDetailService w = new UBCSectionDetailService();
w.initContent(getUniqueCourse((Key) e.getProperty("courseKey")));
e.setProperty("generalSeats", w.getGenSeatsRemain());
e.setProperty("restrictedSeats", w.getRestrictSeatsRemain());
datastore.put(e);
if (getContactEntryEntityList(e.getKey()).isEmpty()) {
datastore.delete(e.getKey());
datastore.delete((Key) e.getProperty("courseKey"));
}
}
log.info("Cache successfully updated");
}
private static final String EMAIL_NOTIFICATION = "Course Information Update: <DEPARTMENT> <COURSE> <SECTION> has <NUMBER_OF_SEATS> <SEAT_TYPE> seat(s) remaining at <TIMESTAMP>. Please visit this link to register(requires CWL authentication): https://courses.students.ubc.ca/cs/main?pname=subjarea&tname=subjareas&req=5&dept=<DEPARTMENT>&course=<COURSE>§ion=<SECTION>";
private static final String SMS_NOTIFICATION = "Course Information Update: <DEPARTMENT> <COURSE> <SECTION> has <NUMBER_OF_SEATS> <SEAT_TYPE> seat(s) remaining at <TIMESTAMP>. Please visit UBC SSC to register.";
private String prepareMessage(String template, String dept, String course,
String section, long numberOfSeats, String seatType) {
String s = template;
s = s.replaceAll("<DEPARTMENT>", dept);
s = s.replaceAll("<COURSE>", course);
s = s.replaceAll("<SECTION>", section);
s = s.replaceAll("<NUMBER_OF_SEATS>", "" + numberOfSeats);
s = s.replaceAll("<SEAT_TYPE>", seatType);
Date d = Calendar.getInstance(TimeZone.getTimeZone("PST")).getTime();
s = s.replaceAll("<TIMESTAMP>", d.toString());
return s;
}
public void notifyAvailableCourses() throws EntityNotFoundException {
List<UniqueCourseObject> cucol = getCacheUniqueCourseObjectList();
for (Iterator i = cucol.iterator(); i.hasNext();) {
UniqueCourseObject uco = (UniqueCourseObject) i.next();
Entity e = getCacheEntity(uco);
long gSeats = (Long) e.getProperty("generalSeats");
long rSeats = (Long) e.getProperty("restrictedSeats");
List<Entity> ceel = getContactEntryEntityList(e.getKey());
for (Iterator j = ceel.iterator(); j.hasNext();) {
Entity ce = (Entity)j.next();
ContactInformationObject cio = getContactInformation((Key)ce.getProperty("contactKey"));
if (cio.getSeatConfig() == 1 && gSeats > 0) {
// notify gen seats avail
if (cio.getNotifyConfig() == 1
&& cio.getEmailAddress() != null
&& cio.getEmailAddress() != "") {
// email notify
EmailNotifier en = new EmailNotifier();
String msg = prepareMessage(EMAIL_NOTIFICATION,
uco.getDepartmentName(), uco.getCourseNumber(),
uco.getSectionNumber(), gSeats, "general");
EmailNotifier.sendMessage(cio.getEmailAddress(), msg);
destroyContactEntry(ce.getKey());
}
if (cio.getNotifyConfig() == 2
&& cio.getPhoneNumber() != null
&& cio.getPhoneNumber() != ""
&& cio.getCarrier() != CARRIER.NULL) {
// sms notify
SMSNotifier smsn = new SMSNotifier();
String msg = prepareMessage(SMS_NOTIFICATION,
uco.getDepartmentName(), uco.getCourseNumber(),
uco.getSectionNumber(), gSeats, "general");
SMSNotifier.sendMessage(cio.getPhoneNumber(),
cio.getCarrier(), msg);
destroyContactEntry(ce.getKey());
}
}
if (cio.getSeatConfig() == 2 && rSeats > 0) {
// notify res seats avail
if (cio.getNotifyConfig() == 1
&& cio.getEmailAddress() != null
&& cio.getEmailAddress() != "") {
// email notify
EmailNotifier en = new EmailNotifier();
String msg = prepareMessage(EMAIL_NOTIFICATION,
uco.getDepartmentName(), uco.getCourseNumber(),
uco.getSectionNumber(), rSeats, "restricted");
EmailNotifier.sendMessage(cio.getEmailAddress(), msg);
destroyContactEntry(ce.getKey());
}
if (cio.getNotifyConfig() == 2
&& cio.getPhoneNumber() != null
&& cio.getPhoneNumber() != ""
&& cio.getCarrier() != CARRIER.NULL) {
// sms notify
SMSNotifier smsn = new SMSNotifier();
String msg = prepareMessage(SMS_NOTIFICATION,
uco.getDepartmentName(), uco.getCourseNumber(),
uco.getSectionNumber(), rSeats, "restricted");
SMSNotifier.sendMessage(cio.getPhoneNumber(),
cio.getCarrier(), msg);
destroyContactEntry(ce.getKey());
}
}
}
}
}
private Entity createContactEntryEntity(UniqueCourseObject uco,
Key contactKey) {
Entity e = new Entity("Contact Entry", getCacheEntity(uco).getKey());
e.setProperty("contactKey", contactKey);
Transaction txn = datastore.beginTransaction();
datastore.put(e);
txn.commit();
return e;
}
private List<Entity> getContactEntryEntityList(Key cacheKey) {
Query q = new Query("Contact Entry");
q.setAncestor(cacheKey);
List<Entity> results = datastore.prepare(q).asList(
FetchOptions.Builder.withDefaults());
return results;
}
private void destroyContactEntry(Key contactEntryKey) throws EntityNotFoundException {
Entity e = datastore.get(contactEntryKey);
Key k = (Key)e.getProperty("contactKey");
datastore.delete(k);
datastore.delete(contactEntryKey);
}
private Entity getContactInformationEntity(ContactInformationObject cio) {
Query q = new Query("Contact Information");
q.addFilter("emailAddress", FilterOperator.EQUAL, cio.getEmailAddress());
q.addFilter("phoneNumber", FilterOperator.EQUAL, cio.getPhoneNumber());
q.addFilter("seatConfig", FilterOperator.EQUAL, cio.getSeatConfig());
q.addFilter("notifyConfig", FilterOperator.EQUAL, cio.getNotifyConfig());
q.addFilter("carrier", FilterOperator.EQUAL, cio.getCarrier()
.getGateway());
return datastore.prepare(q).asSingleEntity();
}
private Entity createContactInformationEntity(ContactInformationObject cio) {
Transaction txn = datastore.beginTransaction();
Key k = KeyFactory.createKey("Contact Information Set", "CONTACT_SET");
Entity e = new Entity("Contact Information", k);
e.setProperty("emailAddress", cio.getEmailAddress());
e.setProperty("phoneNumber", cio.getPhoneNumber());
e.setProperty("seatConfig", cio.getSeatConfig());
e.setProperty("notifyConfig", cio.getNotifyConfig());
e.setProperty("carrier", cio.getCarrier().getGateway());
datastore.put(e);
txn.commit();
return e;
}
private void destroyContactInformationEntity(Key contactKey) {
Transaction txn = datastore.beginTransaction();
datastore.delete(contactKey);
txn.commit();
}
private Entity createUniqueCourseEntity(UniqueCourseObject uco) {
Transaction txn = datastore.beginTransaction();
Key k = KeyFactory.createKey("Unique Course Set", "COURSE_ID_SET");
Entity e = new Entity("Unique Course", k);
e.setProperty("departmentName", uco.getDepartmentName());
e.setProperty("courseNumber", uco.getCourseNumber());
e.setProperty("sectionNumber", uco.getSectionNumber());
datastore.put(e);
txn.commit();
return e;
}
private void destroyUniqueCourseEntity(Key courseKey) {
Transaction txn = datastore.beginTransaction();
datastore.delete(courseKey);
txn.commit();
}
private Entity getCacheEntity(UniqueCourseObject uco) {
Query q = new Query("Cache");
q.addFilter("courseKey", Query.FilterOperator.EQUAL,
getUniqueCourseEntity(uco).getKey());
return datastore.prepare(q).asSingleEntity();
}
private Entity getUniqueCourseEntity(UniqueCourseObject uco) {
Query q = new Query("Unique Course");
q.addFilter("departmentName", Query.FilterOperator.EQUAL,
uco.getDepartmentName());
q.addFilter("courseNumber", Query.FilterOperator.EQUAL,
uco.getCourseNumber());
q.addFilter("sectionNumber", Query.FilterOperator.EQUAL,
uco.getSectionNumber());
PreparedQuery pq = datastore.prepare(q);
return pq.asSingleEntity();
}
private boolean checkCourseExist(UniqueCourseObject uco) {
Query q = new Query("Unique Course");
q.addFilter("departmentName", Query.FilterOperator.EQUAL,
uco.getDepartmentName());
q.addFilter("courseNumber", Query.FilterOperator.EQUAL,
uco.getCourseNumber());
q.addFilter("sectionNumber", Query.FilterOperator.EQUAL,
uco.getSectionNumber());
PreparedQuery pq = datastore.prepare(q);
if (pq.countEntities(FetchOptions.Builder.withDefaults()) == 0)
return false;
return true;
}
private boolean checkNotifierExist(UniqueCourseObject uco,
ContactInformationObject cio) throws EntityNotFoundException {
List<ContactInformationObject> ciol = getContactEntryList(uco);
for (Iterator i = ciol.iterator(); i.hasNext();) {
ContactInformationObject cio2 = (ContactInformationObject) i.next();
if (cio2.equals(cio))
return true;
}
return false;
}
}